library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;


entity icache is port(
	clk, nrst : in  std_logic;
	tag_in    : in  std_logic_vector(25 downto 0);
	data_in   : in  std_logic_vector(31 downto 0);
	data_out  : out std_logic_vector(31 downto 0);
	index_in  : in  std_logic_vector(3 downto 0);
	hit       : out std_logic;
	icache_en : in  std_logic);
end icache;



architecture instr_cache of icache is
	type   ram is array(15 downto 0) of std_logic_vector(31 downto 0);
	type   tagg is array(15 downto 0) of std_logic_vector(25 downto 0);
	type   validd is array(15 downto 0) of std_logic;
	signal validd1, validd2 : validd;
	signal ram1, ram2       : ram;
	signal tagg1, tagg2     : tagg;

begin
	regg : process(clk, nrst)
	begin
		if nrst = '0' then
			for i in 0 to 15 loop
				validd1 (i) <= '0';
			end loop;

		elsif falling_edge(clk) then
			for i in 0 to 15 loop
				validd1(i) <= validd2(i);
				ram1 (i)   <= ram2(i);
				tagg1(i)   <= tagg2(i);
			end loop;

		end if;
	end process regg;

	nextstate : process(validd1, ram1, tagg1, tag_in, data_in, icache_en, index_in)
		variable var1 : integer range 0 to 15;
	begin
		
		var1 := to_integer(unsigned(index_in));
		for i in 0 to 15 loop
			tagg2(i)   <= tagg1(i);
			ram2(i)    <= ram1(i);
			validd2(i) <= validd1(i);
		end loop;

		if icache_en = '1' then
			tagg2(var1) <= tag_in;
			ram2(var1) <= data_in;
			validd2(var1) <= '1';
		end if;

		data_out <= ram1(var1);
		if tag_in = tagg1(var1) and validd1(var1) = '1' then
			hit <= '1';
		else
			hit <= '0';
		end if;
		
	end process nextstate;
end;

